#include "PeaksAndValleys.h"
#include "GameApp.h"
#include "Scene/SceneManager.h"
#include "Scene/Engine.h"
#include "Renderer/D3D10RenderDevice.h"
#include "Renderer/HardwareResourceManager.h"
#include "Renderer/EffectTechnique.h"


#include "Common/Constants.h"
#include "Common/CommonTypes.h"
#include "Camera/BaseCamera.h"
#include "Utility/Utility.h"
#include "Renderer/RenderObject.h"
#include "Renderer/MeshBuffer.h"
#include "Renderer/VertexBuffer.h"
#include "Renderer/IndexBuffer.h"
#include "Renderer/RenderSystem.h"
struct PeakValleyVertex
{
	CVector3  position;
	CColor    color;
};

CPeakValleySceneEntity::CPeakValleySceneEntity( 
			EntityID entityID, const std::string& entityName, ESceneEntityType entityType )
	: CSceneEntity(entityID, entityName, entityType)
	, m_dwRowNum(0)
	, m_dwColNum(0)
	, m_dwVertexNum(0)
	, m_dwFaceNum(0)
	, m_pRenderObj(NULL)

{

}

CPeakValleySceneEntity::~CPeakValleySceneEntity()
{
	if (m_pRenderObj && m_pRenderObj->pMeshBuffer)
	{
		m_pRenderObj->pMeshBuffer->Release();
		SAFE_DELETE(m_pRenderObj->pMeshBuffer);
		SAFE_DELETE(m_pRenderObj);
	}
	m_dwRowNum = m_dwColNum = 0;
	m_dwVertexNum = m_dwFaceNum = 0;
}


bool CPeakValleySceneEntity::Init()
{
	m_pRenderObj = new CMeshRenderObject;
	CreateGeometry(129, 129, 2.0f);

	return true;
}

bool CPeakValleySceneEntity::Load( const std::string& filepath )
{
	return true;
}

void CPeakValleySceneEntity::Update( float fTime )
{
	D3DXMatrixIdentity(&m_pRenderObj->mMatrix);
}

void CPeakValleySceneEntity::Render()
{
	
	
	GetEngine()->GetRenderer()->Render(*m_pRenderObj);
}

void CPeakValleySceneEntity::CreateGeometry( UINT32 dwRowNum, UINT32 dwColNum, float dx )
{
	m_dwRowNum = dwRowNum;
	m_dwColNum = dwColNum;

	m_dwVertexNum = dwRowNum * dwColNum;
	m_dwFaceNum   = (dwRowNum - 1) * (dwColNum - 1) * 2;

	float fHalfWidth  = (dwRowNum - 1) * dx * 0.5f;
	float fHalfDepth  = (dwColNum - 1) * dx * 0.5f;

	// Vertex Buff
	std::vector<PeakValleyVertex>  vecVertices(m_dwVertexNum);
	for(UINT32 i = 0; i < dwRowNum; i++)
	{
		float z = fHalfDepth - i * dx;
		for (UINT32 j = 0; j < dwColNum; j++)
		{
			float x = -fHalfWidth + j * dx;

			float y = _GetHeight(x, z);

			vecVertices[i * dwRowNum + j].position = CVector3(x, y, z);
			if (y < -10.f)
				vecVertices[i * dwRowNum + j].color = BEACH_SAND;
			else if( y < 5.0f)
				vecVertices[i * dwRowNum + j].color = LIGHT_YELLOW_GREEN;
			else if( y < 12.f)
				vecVertices[i * dwRowNum + j].color = DARK_YELLOW_GREEN;
			else if( y < 20.f)
				vecVertices[i * dwRowNum + j].color = DARKBROWN;
			else 
				vecVertices[i * dwRowNum + j].color = WHITE;
		}
	}

	// Index Buffer
	std::vector<UINT32>  vecIndices(m_dwFaceNum * 3);
	int k = 0;
	for(UINT32 i = 0; i < dwRowNum - 1; i++)
	{
		for (UINT32 j = 0; j < dwColNum - 1; j++)
		{
			vecIndices[k]     = i * dwColNum + j;
			vecIndices[k + 1] = i * dwColNum + j + 1;
			vecIndices[k + 2] = (i + 1) * dwColNum + j;

			vecIndices[k + 3] = (i + 1) * dwColNum + j;
			vecIndices[k + 4] = i * dwColNum + j + 1;
			vecIndices[k + 5] = (i + 1) * dwColNum + j + 1;

			k += 6;
		}
	}

	CHardwareResourceManager *pHWResMgr = GetEngine()->GetHwResMgr();
	CVertexBuffer *pVertBuf = pHWResMgr->CreateVertexBuffer(HBU_DYNAMIC, sizeof(PeakValleyVertex), m_dwVertexNum);
	PeakValleyVertex *pData = (PeakValleyVertex*)pVertBuf->Lock();
	UINT32 dwSizeInBytes = pVertBuf->m_dwVertexSize* pVertBuf->m_dwVertexCount;
	memcpy(pData, &vecVertices[0], dwSizeInBytes);
	pVertBuf->UnLock();

	CIndexBuffer *pIndexBuf = pHWResMgr->CreateIndexBuffer(HBU_DYNAMIC, vecIndices.size());
	UINT32* pIndexData = (UINT32*)pIndexBuf->Lock();
	memcpy(pIndexData, &vecIndices[0], pIndexBuf->m_dwIndexCount * sizeof(UINT32));
	pIndexBuf->UnLock();

	m_pRenderObj->pMeshBuffer = new CMeshBuffer(pVertBuf, pIndexBuf);
}

float CPeakValleySceneEntity::_GetHeight( float fX, float fZ )
{
	return 0.3f * (fZ * sinf(0.1f * fX) + fX * cosf(0.1f * fZ));
}

CPeaksAndValleysModule::CPeaksAndValleysModule()
{
	m_SceneID  = -1;
	m_EntityID = -1;
}

CPeaksAndValleysModule::~CPeaksAndValleysModule()
{
	m_SceneID  = -1;
	m_EntityID = -1;
}

void CPeaksAndValleysModule::Init()
{
	DBG_ASSERT(m_SceneID == -1);

	CSceneManager* pSceneMgr = GetEngine()->GetSceneMgr();
	CScene *pScene = pSceneMgr->CreateScene("CPeaksAndValleysScene");
	pScene->Init();

	CPeakValleySceneEntity* pEntity = 
		pScene->CreateEntity<CPeakValleySceneEntity>("PeakValley", SCENE_ENTITY_STATIC_MESH);
	pEntity->Init();	

	m_SceneID  = pScene->GetID();
	m_EntityID = pEntity->GetID();

	pSceneMgr->ActivateScene(m_SceneID);
}

void CPeaksAndValleysModule::UnInit()
{
	DBG_ASSERT(m_SceneID != -1);

	CSceneManager* pSceneMgr = GetEngine()->GetSceneMgr();

	pSceneMgr->DestroyScene(m_SceneID);
}

void CPeaksAndValleysModule::Update( float fTime )
{
	static float s_CameraCircleRadius = 300.0f;

	const GameTimer& gameTimer = GetApp()->GetGameTimer();
	float fX = s_CameraCircleRadius * cosf(0.5f * gameTimer.getGameTime());
	float fZ = s_CameraCircleRadius * sinf(0.5f * gameTimer.getGameTime());
	float fY = 50.0f * sinf(0.5f * gameTimer.getGameTime()) + 300.0f;

	CBaseCamera* pCamera = GetApp()->GetGameWorld()->GetCamera();
	pCamera->SetPosition(CVector3(fX, fY, fZ));
}
